#ifndef __IPOLIGON3D_H__
#define __IPOLIGON3D_H__

#include "CTypes.h"
#include <string.h>

typedef enum VectorOrder
{
	VO_ANTICLOCK	=	0,
	VO_CLOCK		=	1,
} VectorOrder;

class IPoligon3D
{
protected:
	u32 NumVertex;
	u32 Index;
	vPos *VectorArray;
	vPos Normal[LEN_VEC];
	bool AddingVectors;
	VectorOrder ActualVO;
	vPos *VectorAntiClock;
	vPos *VectorClock;
public:
	IPoligon3D(u32 nv):NumVertex(nv),Index(0),AddingVectors(false),ActualVO(VO_ANTICLOCK)
	{
		VectorArray = new vPos[NumVertex*LEN_VEC];
		VectorAntiClock = new vPos[NumVertex*LEN_VEC];
		VectorClock = new vPos[NumVertex*LEN_VEC];
	}

	virtual ~IPoligon3D()
	{
		DEALLOCATEARRAY(VectorArray);
		DEALLOCATEARRAY(VectorAntiClock);
		DEALLOCATEARRAY(VectorClock);
	}

	inline void ResetVectorCounter()	{	Index=0;	}

	inline void BeginVectors(VectorOrder vo=VO_ANTICLOCK)
	{
		ResetVectorCounter();
		AddingVectors = true;
		ActualVO = vo;
	}

	inline void EndVectors()
	{
		AddingVectors = false;

		switch (ActualVO)
		{
			default:
			case VO_ANTICLOCK:
			{
				memcpy(VectorAntiClock,VectorArray,Index*sizeof(vPos));
				s32 j=0;
				for (s32 i=Index - 1;i>=0;i--)
				{
					VectorClock[j] = VectorAntiClock[i];
					j++;
				}
			}
			break;

			case VO_CLOCK:
			{
				memcpy(VectorClock,VectorArray,Index*sizeof(vPos));
				s32 j=0;
				for (s32 i=Index - 1;i>=0;i--)
				{
					VectorClock[j] = VectorAntiClock[i];
					j++;
				}
			}
			break;
		}

		UpdateNormal();
	}

	inline void AddVector(vector3dvpos *v)
	{
		VectorArray[Index] = (vPos)v->X;
		Index++;
		VectorArray[Index] = (vPos)v->Y;
		Index++;
		VectorArray[Index] = (vPos)v->Z;
		Index++;
	}

	inline void AddVector(vPos x,vPos y,vPos z)
	{
		VectorArray[Index] = x;
		Index++;
		VectorArray[Index] = y;
		Index++;
		VectorArray[Index] = z;
		Index++;
	}

	inline void AddVector(vPos *v)
	{
		VectorArray[Index] = v[0];
		Index++;
		VectorArray[Index] = v[1];
		Index++;
		VectorArray[Index] = v[2];
		Index++;
	}

	inline vector3dvpos GetMinimum()
	{
		vector3dvpos Temp(0.0,0.0,0.0);
		bool MinimumXUpdated=false;
		bool MinimumYUpdated=false;
		bool MinimumZUpdated=false;

		for (u32 i=0;i<NumVertex;i++)
		{
			vPos *v1 = &(VectorArray[i*LEN_VEC]);

			if (v1[0] < Temp.X || !MinimumXUpdated)
			{
				Temp.X = v1[0];
				MinimumXUpdated = true;
			}

			if (v1[1] < Temp.Y || !MinimumYUpdated)
			{
				Temp.Y = v1[1];
				MinimumYUpdated = true;
			}

			if (v1[2] < Temp.Z || !MinimumZUpdated)
			{
				Temp.Z = v1[2];
				MinimumZUpdated = true;
			}
		}
		return Temp;
	}

	inline void UpdateNormal()
	{
		vector3dvpos a(&VectorArray[3*LEN_VEC]);
		vector3dvpos b(&VectorArray[2*LEN_VEC]);
		vector3dvpos c(&VectorArray[LEN_VEC]);

		vector3dvpos u(b - a);
		vector3dvpos v(c - a);

		vector3dvpos n(u.ProductoCruz(v));
		n.Normalize();
		Normal[0] = n.X;
		Normal[1] = n.Y;
		Normal[2] = n.Z;
	}

	inline vPos GetLenX()
	{
		if (Index>1)
		{
			vPos *v1 = &(VectorArray[0]);
			vPos *v2 = &(VectorArray[LEN_VEC]);

			return ABS(v2[0] - v1[0]);
		}
		return 0.0;
	}

	inline vPos GetLenY()
	{
		if (Index>2)
		{
			vPos *v1 = &(VectorArray[0]);
			vPos *v2 = &(VectorArray[LEN_VEC*2]);

			return ABS(v2[1] - v1[1]);
		}
		return 0.0;
	}

	inline vPos *GetVector(u32 Pos)					{	return &(VectorArray[Pos*LEN_VEC]);		}
	inline vPos *GetCompleteVectorClock()			{	return VectorClock;						}
	inline vPos *GetCompleteVectorAntiClock()		{	return VectorAntiClock;					}
	inline vPos *GetNormal()						{	return Normal;							}
	inline u32 GetNumVectors()						{	return NumVertex;						}

};
#endif
